from django.db import models
from django.db.models.loading import get_model

class Error(Exception):
	pass
class InvalidModelNameError(Error):
	pass
class InvalidReferencePrimaryKeyError(Error):
	pass
class ColumnNameError(Error):
	pass

class ref_aux:
	def __init__(self, ref):
		self.ref=ref
	def fn(self, x):
		try:
			return self.ref.objects.get(pk=x)
		except self.ref.DoesNotExist:
			raise InvalidReferencePrimaryKeyError(x)

def get_processor(field):
	if isinstance(field, models.ForeignKey):
		ref=field.rel.to
		return ref_aux(ref).fn
	elif isinstance(field, models.BooleanField):
		return lambda x: x.lower()=='true'
	elif isinstance(field, models.IntegerField):
		return lambda x: int(x)
	elif isinstance(field, models.FloatField):
		return lambda x: float(x)
	elif isinstance(field, models.ManyToManyField):
		ref=field.rel.to
		return ref_aux(ref).fn
	else:
		return lambda x: x
	

def import_block(lines):
	model_name=lines[0]
	model=get_model('data', model_name)
	if not model:
		raise InvalidModelNameError(model_name)
	fields=model.get_fields_dict()

	cols=lines[1].split('\t')
	processors={}
	m2m_fields=[]
	for col in cols:
		if not col in fields:
			raise ColumnNameError(col)
		field=fields[col]
		processors[col]=get_processor(field)
		if isinstance(field, models.ManyToManyField):
			m2m_fields.append(col)
			
			
	model_key=model._meta.pk.name
	if not model_key in cols:
		model_key=None
	
	stats={'added': 0, 'updated':0}
	
	data_strings=lines[2:]
	for data_string in data_strings:
		if data_string=='':
			continue
		data=data_string.split('\t')
		params={}
		m2m_data={}
		for i in range(0,len(data)):
			col=cols[i]
			if col in m2m_fields:
				m2m_data[col]=data[i]
			else:
				params[col]=processors[col](data[i])
		import pprint
		pprint.pprint(params)
		obj=None
		if model_key:
			try:
				obj=model.objects.get(pk=params[model_key])
				stats['updated']+=1
				del(params[model_key])
				for col, val in params.iteritems():
					setattr(obj, col, val)
			except model.DoesNotExist:
				pass
		if not obj:
			obj=model(**params)
			stats['added']+=1
		obj.save()
		
		for col, data in m2m_data.iteritems():
			if not data:
				continue
			items=map(processors[col], data.split(','))
			for item in items:
				getattr(obj, col).add(item)
			
	return stats 	

def import_tables(data_string):
	lines=data_string.splitlines()
	stats=[]
	start=0;
	for i in range(0, len(lines)):
		if lines[i]=='':
			if start!=i:
				stats.append(import_block(lines[start:i]))
			start=i+1
	if start!=len(lines):
		stats.append(import_block(lines[start:]))
	res={'added': 0, 'updated':0}
	for st in stats:
		for x in st:
			res[x]+=st[x]
	return res
